package com.seafood.service.impl;

import com.seafood.dto.TemperatureLogDTO;
import com.seafood.entity.ColdChainRecord;
import com.seafood.entity.TemperatureLog;
import com.seafood.repository.ColdChainRecordRepository;
import com.seafood.repository.TemperatureLogRepository;
import com.seafood.service.TemperatureLogService;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 温度记录服务实现
 */
@Service
@RequiredArgsConstructor
@Transactional
public class TemperatureLogServiceImpl implements TemperatureLogService {
    
    private final TemperatureLogRepository temperatureLogRepository;
    private final ColdChainRecordRepository coldChainRecordRepository;
    
    private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    
    @Override
    public TemperatureLogDTO createTemperatureLog(TemperatureLogDTO logDTO) {
        TemperatureLog log = new TemperatureLog();
        copyDtoToEntity(logDTO, log);
        
        // 检查温度异常
        boolean isAbnormal = checkTemperatureAbnormal(logDTO.getColdChainRecordId(), logDTO.getTemperature()) ||
                            checkHumidityAbnormal(logDTO.getColdChainRecordId(), logDTO.getHumidity());
        log.setIsAbnormal(isAbnormal);
        
        TemperatureLog saved = temperatureLogRepository.save(log);
        return convertToDTO(saved);
    }
    
    @Override
    public List<TemperatureLogDTO> createTemperatureLogs(List<TemperatureLogDTO> logDTOs) {
        return logDTOs.stream()
                .map(this::createTemperatureLog)
                .collect(Collectors.toList());
    }
    
    @Override
    @Transactional(readOnly = true)
    public TemperatureLogDTO getTemperatureLogById(Long id) {
        TemperatureLog log = temperatureLogRepository.findById(id)
                .orElseThrow(() -> new RuntimeException("温度记录不存在"));
        return convertToDTO(log);
    }
    
    @Override
    @Transactional(readOnly = true)
    public List<TemperatureLogDTO> getTemperatureLogsByColdChainRecordId(Long coldChainRecordId) {
        List<TemperatureLog> logs = temperatureLogRepository.findByColdChainRecordIdOrderByRecordTimeDesc(coldChainRecordId);
        return logs.stream().map(this::convertToDTO).collect(Collectors.toList());
    }
    
    @Override
    @Transactional(readOnly = true)
    public Page<TemperatureLogDTO> getRecentTemperatureLogs(Long coldChainRecordId, Pageable pageable) {
        Page<TemperatureLog> logs = temperatureLogRepository.findRecentLogs(coldChainRecordId, pageable);
        return logs.map(this::convertToDTO);
    }
    
    @Override
    @Transactional(readOnly = true)
    public List<TemperatureLogDTO> getAbnormalTemperatureLogs(Long coldChainRecordId) {
        ColdChainRecord record = coldChainRecordRepository.findById(coldChainRecordId)
                .orElseThrow(() -> new RuntimeException("冷链记录不存在"));
        
        List<TemperatureLog> logs = temperatureLogRepository.findByColdChainRecordAndIsAbnormalTrue(record);
        return logs.stream().map(this::convertToDTO).collect(Collectors.toList());
    }
    
    @Override
    @Transactional(readOnly = true)
    public List<TemperatureLogDTO> getTemperatureLogsByRange(Long coldChainRecordId, BigDecimal minTemp, BigDecimal maxTemp) {
        List<TemperatureLog> logs = temperatureLogRepository.findByTemperatureRange(coldChainRecordId, minTemp, maxTemp);
        return logs.stream().map(this::convertToDTO).collect(Collectors.toList());
    }
    
    @Override
    @Transactional(readOnly = true)
    public List<TemperatureLogDTO> getTemperatureLogsByTimeRange(Long coldChainRecordId, LocalDateTime startTime, LocalDateTime endTime) {
        List<TemperatureLog> logs = temperatureLogRepository.findByTimeRange(coldChainRecordId, startTime, endTime);
        return logs.stream().map(this::convertToDTO).collect(Collectors.toList());
    }
    
    @Override
    @Transactional(readOnly = true)
    public List<TemperatureLogDTO> getOfflineDeviceLogs(Long coldChainRecordId) {
        ColdChainRecord record = coldChainRecordRepository.findById(coldChainRecordId)
                .orElseThrow(() -> new RuntimeException("冷链记录不存在"));
        
        List<TemperatureLog> logs = temperatureLogRepository.findByColdChainRecordAndDeviceOnlineFalse(record);
        return logs.stream().map(this::convertToDTO).collect(Collectors.toList());
    }
    
    @Override
    @Transactional(readOnly = true)
    public Map<String, Object> getTemperatureStatistics(Long coldChainRecordId) {
        Object[] stats = temperatureLogRepository.getTemperatureStatistics(coldChainRecordId);
        Map<String, Object> result = new HashMap<>();
        
        if (stats != null && stats.length == 3) {
            result.put("minTemperature", stats[0]);
            result.put("maxTemperature", stats[1]);
            result.put("avgTemperature", stats[2]);
        }
        
        return result;
    }
    
    @Override
    @Transactional(readOnly = true)
    public Map<String, Object> getHumidityStatistics(Long coldChainRecordId) {
        Object[] stats = temperatureLogRepository.getHumidityStatistics(coldChainRecordId);
        Map<String, Object> result = new HashMap<>();
        
        if (stats != null && stats.length == 3) {
            result.put("minHumidity", stats[0]);
            result.put("maxHumidity", stats[1]);
            result.put("avgHumidity", stats[2]);
        }
        
        return result;
    }
    
    @Override
    @Transactional(readOnly = true)
    public boolean checkTemperatureAbnormal(Long coldChainRecordId, BigDecimal temperature) {
        ColdChainRecord record = coldChainRecordRepository.findById(coldChainRecordId)
                .orElseThrow(() -> new RuntimeException("冷链记录不存在"));
        
        if (temperature == null) return false;
        
        BigDecimal minTemp = record.getPlannedTempMin();
        BigDecimal maxTemp = record.getPlannedTempMax();
        
        if (minTemp != null && temperature.compareTo(minTemp) < 0) {
            return true;
        }
        
        if (maxTemp != null && temperature.compareTo(maxTemp) > 0) {
            return true;
        }
        
        return false;
    }
    
    @Override
    @Transactional(readOnly = true)
    public boolean checkHumidityAbnormal(Long coldChainRecordId, BigDecimal humidity) {
        ColdChainRecord record = coldChainRecordRepository.findById(coldChainRecordId)
                .orElseThrow(() -> new RuntimeException("冷链记录不存在"));
        
        if (humidity == null) return false;
        
        BigDecimal minHumidity = record.getPlannedHumidityMin();
        BigDecimal maxHumidity = record.getPlannedHumidityMax();
        
        if (minHumidity != null && humidity.compareTo(minHumidity) < 0) {
            return true;
        }
        
        if (maxHumidity != null && humidity.compareTo(maxHumidity) > 0) {
            return true;
        }
        
        return false;
    }
    
    @Override
    @Transactional(readOnly = true)
    public Long countAbnormalLogs(Long coldChainRecordId) {
        return temperatureLogRepository.countAbnormalLogs(coldChainRecordId);
    }
    
    @Override
    @Transactional(readOnly = true)
    public Map<String, Object> generateTemperatureTrendReport(Long coldChainRecordId, LocalDateTime startTime, LocalDateTime endTime) {
        List<TemperatureLog> logs = temperatureLogRepository.findByTimeRange(coldChainRecordId, startTime, endTime);
        
        Map<String, Object> report = new HashMap<>();
        report.put("totalRecords", logs.size());
        report.put("timeRange", Map.of("start", startTime, "end", endTime));
        
        if (!logs.isEmpty()) {
            // 计算温度趋势
            List<Map<String, Object>> temperatureTrend = logs.stream()
                    .map(log -> {
                        Map<String, Object> dataPoint = new HashMap<>();
                        dataPoint.put("time", log.getRecordTime());
                        dataPoint.put("temperature", log.getTemperature());
                        dataPoint.put("humidity", log.getHumidity());
                        dataPoint.put("isAbnormal", log.getIsAbnormal());
                        return dataPoint;
                    })
                    .collect(Collectors.toList());
            
            report.put("temperatureTrend", temperatureTrend);
            
            // 统计异常记录
            long abnormalCount = logs.stream()
                    .mapToLong(log -> log.getIsAbnormal() ? 1 : 0)
                    .sum();
            report.put("abnormalCount", abnormalCount);
            report.put("abnormalRate", (double) abnormalCount / logs.size() * 100);
        }
        
        return report;
    }
    
    @Override
    public void cleanupOldLogs(LocalDateTime cutoffTime) {
        temperatureLogRepository.deleteOldLogs(cutoffTime);
    }
    
    @Override
    public void deleteTemperatureLog(Long id) {
        temperatureLogRepository.deleteById(id);
    }
    
    private void copyDtoToEntity(TemperatureLogDTO dto, TemperatureLog entity) {
        ColdChainRecord record = coldChainRecordRepository.findById(dto.getColdChainRecordId())
                .orElseThrow(() -> new RuntimeException("冷链记录不存在"));
        entity.setColdChainRecord(record);
        
        entity.setTemperature(dto.getTemperature());
        entity.setHumidity(dto.getHumidity());
        entity.setGpsCoordinates(dto.getGpsCoordinates());
        entity.setDeviceId(dto.getDeviceId());
        entity.setDeviceOnline(dto.getDeviceOnline());
        entity.setBatteryLevel(dto.getBatteryLevel());
        entity.setSignalStrength(dto.getSignalStrength());
        
        if (dto.getRecordTime() != null && !dto.getRecordTime().isEmpty()) {
            entity.setRecordTime(LocalDateTime.parse(dto.getRecordTime(), FORMATTER));
        } else {
            entity.setRecordTime(LocalDateTime.now());
        }
    }
    
    private TemperatureLogDTO convertToDTO(TemperatureLog entity) {
        TemperatureLogDTO dto = new TemperatureLogDTO();
        BeanUtils.copyProperties(entity, dto);
        
        dto.setColdChainRecordId(entity.getColdChainRecord().getId());
        dto.setRecordTime(entity.getRecordTime() != null ? entity.getRecordTime().format(FORMATTER) : null);
        dto.setCreatedAt(entity.getCreatedAt() != null ? entity.getCreatedAt().format(FORMATTER) : null);
        
        return dto;
    }
}